#include "Sonar.h"
#include<iostream>
#include<string>

using namespace std;

string g_asType[]=
{
    "Invalid",
    "Global/File",
    "Parentheses",
    "C-Style Comment",
    "C++-style Comment",
    "Block",
    "Bracket",
    "ePreprocessor", //FIXME Remove this. This is actually intelligence?
	"Literal"
};


void Sonar::indent()
{
    for(int i=0;i<m_nIndent;i++)
        cout<<" ";
}


Sonar::Sonar(void)
{
	m_nIndent = 0;

	m_nLoC=0;
	m_nLoCom = 0;
	m_nStatements = 0;
	m_nTotalLines = 0;
	m_nCharacters = 0;
	m_nTabs = 0;
	m_nSpaces = 0;

	m_bLiveTokenDisplay = false;
	m_bScopeChangeDisplay = false;

}

Sonar::~Sonar(void)
{
}

void Sonar::onNewToken(Scope& inScope, Token& inToken)
{
	m_asToken.push_back(inToken.m_sValue);
	m_nCharacters += inToken.m_sValue.length();

	char cToken = char(inToken);
	bool bIsInComment = inScope.isComment();
	bool bIsInCode = inScope.isCode(); 

	switch(cToken)
	{
	case '\n':
		m_nTotalLines++;
		if(bIsInComment)	m_nLoCom++;
		if(bIsInCode)		m_nLoC++;
		m_nCharacters++; //Hack, don't know why \n escapes character increment.
		break;

	case ';':
		if(bIsInCode)		m_nStatements++;
		break;

	case '\t':
		m_nTabs++;
		break;

	case ' ':
		m_nSpaces++;
		break;
	}

	if(m_bLiveTokenDisplay)
		cout<<inToken.m_sValue;
}


void Sonar::onScopeEntry(Scope& inNewScope, Scope& inOldScope)
{
	m_pxCurrentScope = &inNewScope;

    if(m_bScopeChangeDisplay)
	{
		indent();
		cout<<"<<SCOPE>>"<<g_asType[inOldScope.m_eType]<<"-->"<<g_asType[inNewScope.m_eType]<< "<<@" << m_pxLocation->m_nLineNumber<<">>"<< endl;
	}

    m_nIndent++;
}

void Sonar::onScopeExit(Scope& inNewScope, Scope& inOldScope)
{
	m_pxCurrentScope = &inNewScope;
    m_nIndent--;

	if(m_bScopeChangeDisplay)
	{
		indent();
		cout<<"<<SCOPE>>"<<g_asType[inOldScope.m_eType]<<"-->"<<g_asType[inNewScope.m_eType]<< "<<" << m_pxLocation->m_nLineNumber<<">>"<< endl;
	}
}

void Sonar::setLiveDisplay(bool bTokens, bool bScopeChanges)
{
	m_bLiveTokenDisplay = bTokens;
	m_bScopeChangeDisplay = bScopeChanges;
}

void Sonar::printScopeSymbols(Scope* pxScope, SonarOptions* pxOpt)
{
	SymbolTable* pxSymbolTable = pxScope->m_pxSymbolTable;
	int nSymbols = pxSymbolTable->getSize();
	Symbol::Type eType;
	Symbol* pxSymbol;

	for(int i=0; i<nSymbols; i++)
	{
		pxSymbol = pxSymbolTable->m_apxSymbol[i];
		eType = pxSymbol->m_eSymbolType;

		cout<<pxSymbol->m_sName<<"@";
		cout<<pxSymbol->m_xDefinition.m_nLineNumber<<",";
	}

	int nChildren = pxScope->m_apxChild.size();
	Scope *pxCursor;
	for(int i=0; i< nChildren; i++)
	{
		pxCursor = pxScope->m_apxChild[i];
		printScopeSymbols(pxCursor, pxOpt);
	}
	
}


void Sonar::print(SonarOptions *pxOpt)
{
	bool bNoHeading = pxOpt->m_bNoHeading;
	bool bQuiet = pxOpt->m_bModeQuiet;
	pxOpt->m_bFileSummary;
	pxOpt->m_bSymbolTables;
	pxOpt->m_bTokens;
	
	if(pxOpt->m_bTokens)
	{
		int nTokens = m_asToken.size();
		std::string sToken;
		
		if(!bQuiet)
			cout<<"<TOKENS>"<<endl;
		for(int i=0;i<nTokens;i++)
		{
			sToken = m_asToken[i];
			if(sToken == "\n")
				cout<<"~\\n~ "/*<<endl*/;
			else
				cout<<"~"<<sToken<<"~ "/*<<endl*/;
		}

		cout<<endl;
		if(!bQuiet)
			cout<<"</TOKENS>"<<endl;
	}

	if(pxOpt->m_bSymbolTables)
	{
		if(!bQuiet)
			cout<<"<SCOPESYMBOLS>"<<endl;

		printScopeSymbols(m_pxCurrentScope, pxOpt); //This will traverse the children too.

		cout<<endl;
		if(!bQuiet)
			cout<<"</SCOPESYMBOLS>"<<endl;
	}

	if(pxOpt->m_bFileSummary)
	{
		if(!bQuiet)
			cout<<"<SUMMARY>"<<endl;
		if(!bNoHeading)
			cout<<"FileName,Lines,Statements,CodeLines,CommentLines,Tokens,Tabs,Spaces,Characters"<<endl;

		cout<<m_pxLocation->m_sFileName<<",";
		cout<<m_nTotalLines<<",";
		cout<<m_nLoC<<",";
		cout<<m_nLoCom<<",";
		cout<<m_nStatements<<",";
		cout<<m_asToken.size()<<",";
		cout<<m_nTabs<<",";
		cout<<m_nSpaces<<",";
		cout<<m_nCharacters<<endl;

		if(!bQuiet)
			cout<<"</SUMMARY>"<<endl;

	}
}


